package com.mysteel.product.thread;

import java.util.concurrent.*;

/**
 * ProjectName: mail
 * ClassName: ThreadTest
 * Description:
 * date: 2021/02/05/005 16:27
 *
 * @author xiaochao
 */
public class ThreadTest {
    /**
     * int corePoolSize,：核心线程数，线程池初始化后线程池中一直存在的线程数
     * int maximumPoolSize,：最大线程数
     * long keepAliveTime,：存活时间，当线程池的线程数量大于核心线程数量，并且超过了存活时间后还没分配任务，则会被销毁
     * TimeUnit unit,：存活时间单位
     * BlockingQueue<Runnable> workQueue,：阻塞工作组，当并发量大于核心线程数，系统会先把线程放在阻塞工作队列中等待执行
     * ThreadFactory threadFactory,：线程工厂，创建的线程的一些细节
     * RejectedExecutionHandler handler：拒绝策略，当并发量大于 ‘最大线程数+阻塞队列容量 ’后，其它线程的处理策略
     * AbortPolicy：直接丢弃
     */
    public static ThreadPoolExecutor executor = new ThreadPoolExecutor(
            3,
            10,
            3L,
            TimeUnit.SECONDS,
            new LinkedBlockingQueue<Runnable>(10),
            Executors.defaultThreadFactory(),
            new ThreadPoolExecutor.AbortPolicy()
    );
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        System.out.println("main .... start....");

        /*CallableTest callableTest = new CallableTest();
        FutureTask<Integer> futureTask = new FutureTask<Integer>(callableTest);
        new Thread(futureTask).start();
        try {
            // 阻塞等待
            Integer result = futureTask.get();
            System.out.println(result);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }*/

        /**
         * 线程串行化：
         * 1、thenRunAsync：无法获取上一步的执行结果，无返回值
         * 2、thenAcceptAsync：能接受上一步的返回结果，但是无返回值
         * 3、thenApplyAsync：既能接收上一步的返回结果，也能返回当前线程结果
         */
        /*CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {
            System.out.println("当前线程：" + Thread.currentThread().getId());
            int i = 10 / 2;
            System.out.println("计算结果：" + i);
            return i;
        }, executor).thenApplyAsync((res) -> {
            System.out.println(res);
            System.out.println("任务2执行啦...");
            return res * 10;
        }, executor);*/


        /**
         * 线程合并执行完后在执行其它线程
         * 例如：A，B都执行完了，在执行C
         * 注：如果使用Either需要感知任意一个任务执行完成后的返回值，两个任务的返回值类型必须相同，否则代码无法推断返回值类型是什么
         *
         */
        CompletableFuture<Object> future01 = CompletableFuture.supplyAsync(() -> {
            System.out.println("任务一当前线程：" + Thread.currentThread().getId());
            int i = 10 / 2;
            System.out.println("任务一执行结束：" + i);
            try {
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return i;
        }, executor);

        CompletableFuture<Object> future02 = CompletableFuture.supplyAsync(() -> {
            System.out.println("任务二当前线程：" + Thread.currentThread().getId());
            System.out.println("任务二执行结束");
            return "你好，师姐";
        }, executor);

        /*future01.runAfterBothAsync(future02, () -> {
            System.out.println("任务三执行...");
        }, executor);*/

        /*future01.thenAcceptBothAsync(future02,(r1,r2) ->{
            System.out.println("任务一返回结果：" + r1 + ",任务二返回结果：" + r2);
            System.out.println("任务三开始执行...");
        },executor);*/

        /*CompletableFuture<String> future = future01.thenCombineAsync(future02, (r1, r2) -> {
            System.out.println("任务三开始执行...");
            return r1 + "20，" + r2;
        }, executor);*/

        /**
         * 两个任务只要有一个完成后执行下一个任务
         * 例：A、B中有一个完成就执行C
         */
        CompletableFuture<String> future = future01.applyToEitherAsync(future02, (r1) -> {
            System.out.println("让我看看是哪个完成了：" + r1);
            System.out.println("五千年终于轮到我上场...");
            return "你好，师娘";
        }, executor);

        System.out.println(future.get());


        System.out.println("main .... end....");
    }

    public static class CallableTest implements Callable<Integer>{

        @Override
        public Integer call() throws Exception {
            System.out.println("当前线程：" + Thread.currentThread().getId());
            int i = 10 / 2;
            Thread.sleep(5000);
            System.out.println("计算结果：" + i);
            return i;
        }
    }
}
